Italian restaurants in NYC
1. Italian restaurants in NYC
2. Italian restaurants in NYC
No matter where you are, or where you’ve been, if you’re taking this course, my guess is that you’ve been to a restaurant before. And if you’re in Europe or North America, there’s an excellent chance that you’ve been to an Italian restaurant. The Italian restaurants in New York City are legendary, and it’s time to put your newly-developed regression modeling skills to work to understand how they operate. What are the factors that contribute to a price of a meal at Italian restaurants in New York City? We will address this question with a series of multiple regression models.
3. Zagat guide
The Zagat guide is an influential review of restaurants. They are made famous by their use of selective quotes from actual diners to build a pithy description of each restaurant. But we won’t be working with the text. Rather, we’ll be working with the numeric reviews you see posted here. Each restaurant is rated on a scale of 0 to 30 for the quality of its food, decor, and service. The average price of a meal—which includes one drink and a tip—will be our response variable. How do these factors influence the average price of a meal?
4. Exploring the data
Our data come in the form of Zagat reviews from 168 Italian restaurants in New York City from 2001. The glimpse() function can help you get a sense of how the variables are encoded and what values they typically take on. The East variable records whether the restaurant is located east or west of Fifth Avenue, which historically divides the island of Manhattan.
glimpse(nyc)
Rows: 168
Columns: 7
$ Case <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,…
$ Restaurant <chr> "Daniella Ristorante", "Tello's Ristorante", "…
$ Price <int> 43, 32, 34, 41, 54, 52, 34, 34, 39, 44, 45, 47…
$ Food <int> 22, 20, 21, 20, 24, 22, 22, 20, 22, 21, 19, 21…
$ Decor <int> 18, 19, 13, 20, 19, 22, 16, 18, 19, 17, 17, 19…
$ Service <int> 20, 19, 18, 17, 21, 21, 21, 21, 22, 19, 20, 21…
$ East <int> 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1…
5. EDA
Before we can sensibly build models, we should spend some time exploring the data. How are the variables distributed? How are they related to one another? What patterns are present? The pairs() function can help us explore these relationships visually. It shows a grid of scatterplots for each pair of variables in the nyc data frame. It’s easy to see that, for example, Price and Decor are strongly correlated, while Case and Food are uncorrelated.
nyc$Restaurant <- factor(nyc$Restaurant)
pairs(nyc)

6. Let’s practice!
Now it’s time for you to sink your teeth into these data.
Exploratory data analysis
Multiple regression can be an effective technique for understanding how a response variable changes as a result of changes to more than one explanatory variable. But it is not magic – understanding the relationships among the explanatory variables is also necessary, and will help us build a better model. This process is often called exploratory data analysis (EDA) and is covered in another DataCamp course.
One quick technique for jump-starting EDA is to examine all of the pairwise scatterplots in your data. This can be achieved using the pairs() function. Look for variables in the nyc data set that are strongly correlated, as those relationships will help us check for multicollinearity later on.
Which pairs of variables appear to be strongly correlated?
cor(nyc[, -c(2)])
Case Price Food Decor Service
Case 1.0000000 -0.2221911 -0.2030358 -0.11965518 -0.2332600
Price -0.2221911 1.0000000 0.6270435 0.72435248 0.6411402
Food -0.2030358 0.6270435 1.0000000 0.50391610 0.7945248
Decor -0.1196552 0.7243525 0.5039161 1.00000000 0.6453306
Service -0.2332600 0.6411402 0.7945248 0.64533055 1.0000000
East -0.6427551 0.1866302 0.1803706 0.03574929 0.2090941
East
Case -0.64275505
Price 0.18663024
Food 0.18037061
Decor 0.03574929
Service 0.20909408
East 1.00000000
A: Food and Service
SLR models
Based on your knowledge of the restaurant industry, do you think that the quality of the food in a restaurant is an important determinant of the price of a meal at that restaurant? It would be hard to imagine that it wasn’t. We’ll start our modeling process by plotting and fitting a model for Price as a function of Food.
On your own, interpret these coefficients and examine the fit of the model. What does the coefficient of Food mean in plain English? “Each additional rating point of food quality is associated with a…”
Instructions
- Use
ggplot to make a scatter plot for Price as a function of Food.
- Use
lm() to fit a simple linear regression model for Price as a function of Food.
# Price by Food plot
ggplot(data = nyc, aes(x = Food, y = Price)) +
geom_point()

# Price by Food model
lm(Price ~ Food, data = nyc)
Call:
lm(formula = Price ~ Food, data = nyc)
Coefficients:
(Intercept) Food
-17.832 2.939
What does the simple linear model say about how food quality affects price?
Incorporating another variable
1. Incorporating another variable
2. Fifth Avenue
Fifth Avenue is one the most well-known streets in the world, renowned for its flagship stores for shopping, landmark hotels, and internationally-recognized sites. A walk down 5th Avenue from Central Park to Washington Square Park would take you past the Plaza Hotel, Trump Tower, Saks Fifth Avenue, the New York Public Library, the Empire State Building, and the Flatiron building.
3. CUNY
It would also take you past the Graduate Center of the City University of New York, where I studied for my doctoral degree. Good times!
4. Dividing the City
5th Avenue divides the island of Manhattan vertically. The city’s east side has historically been home to expensive residences and opulent attractions. Maybe everything is more expensive on the East side. Maybe even food is more expensive on the east side. Do Italian restaurants located on the east side of 5th Avenue tend to charge more? How much more?
5. The price of location
It’s certainly true that the average price of a meal for restaurants located on the east side of Manhattan was higher than it was for restaurants on the west side. The table above shows that they charged about $3 point 58 more, on average. But does this figure really represent the premium for being on the east side? Could it be the case that the restaurants on the east side also had better food, and that is what was driving the increase in price? You’ll explore this question in the exercises.
nyc %>%
group_by(East) %>%
summarize(mean_price = mean(Price))
6. Service
Another important consideration in dining out is the quality of the service. Are people willing to pay more for higher quality service, even if the food doesn’t taste any better? How much more? How does the average price of meal vary with respect to the quality of the food and the service? It’s up to you to figure it out.
7. Let’s practice!
These next exercises will allow you to delve into these questions.
Parallel lines with location
In real estate, a common mantra is that the three most important factors in determining the price of a property are “location, location, and location.” If location drives up property values and rents, then we might imagine that location would increase a restaurant’s costs, which would result in them having higher prices. In many parts of New York, the east side (east of 5th Avenue) is more developed and perhaps more expensive. [This is increasingly less true, but was more true at the time these data were collected.]
Let’s expand our model into a parallel slopes model by including the East variable in addition to Food.
Use lm() to fit a parallel slopes model for Price as a function of Food and East. Interpret the coefficients and the fit of the model. Can you explain the meaning of the coefficient on East in simple terms? Did the coefficient on Food change from the previous model? If so, why? Did it change by a lot or just a little?
Identify the statement that is FALSE:
Possible Answers
Each additional rating point of food quality is associated with a $2.88 increase in the expected price of meal, after controlling for location.
The premium for an Italian restaurant in NYC associated with being on the east side of 5th Avenue is $1.46, after controlling for the quality of the food.
The change in the coefficient of food from $2.94 in the simple linear model to $2.88 in this model has profound practical implications for restaurant owners.
lm(Price ~ Food, data = nyc)
Call:
lm(formula = Price ~ Food, data = nyc)
Coefficients:
(Intercept) Food
-17.832 2.939
lm(Price ~ Food + East, data = nyc)
Call:
lm(formula = Price ~ Food + East, data = nyc)
Coefficients:
(Intercept) Food East
-17.430 2.875 1.459
A: 3
A plane in 3D
One reason that many people go to a restaurant—apart from the food—is that they don’t have to cook or clean up. Many people appreciate the experience of being waited upon, and we can all agree that the quality of the service at restaurants varies widely. Are people willing to pay more for better restaurant Service? More interestingly, are they willing to pay more for better service, after controlling for the quality of the food?
Multiple regression gives us a way to reason about these questions. Fit the model with Food and Service and interpret the coefficients and fit. Did the coefficient on Food change from the previous model? What do the coefficients on Food and Service tell you about how these restaurants set prices?
Next, let’s visually assess our model using plotly. The x and y vectors, as well as the plane matrix, have been created for you.
Instructions
- Use
lm() to fit a multiple regression model for Price as a function of Food and Service.
- Use
plot_ly to draw 3D scatterplot for Price as a function of Food and Service by mapping the z variable to the response and the x and y variables to the explanatory variables. Place the food quality on the x-axis and service rating on the y-axis.
- Use
add_surface() to draw a plane through the cloud of points using the object plane.
# fit model
lm(Price ~ Food + Service, data = nyc)
Call:
lm(formula = Price ~ Food + Service, data = nyc)
Coefficients:
(Intercept) Food Service
-21.159 1.495 1.704
# draw 3D scatterplot
p <- plot_ly(data = nyc, z = ~Price, x = ~Food, y = ~Service, opacity = 0.6) %>%
add_markers(marker = list(size = 2))
# draw a plane
p %>%
add_surface(x = ~x, y = ~y, z = ~plane, showscale = FALSE)
Higher dimensions
1. Higher dimensions
2. Decor
The last criteria for the Zagat review is decor. This refers to the visual presentation of the restaurant: the furniture, the wall adornments, and the overall ambience. Clearly, restaurants vary widely in the quality of their decor. But how does the perceived quality of decor vary with the price of a meal? And how is the effect moderated by the quality of food and service?
3. Building a full model
In what follows, you will build more complex models for the price of a meal at an Italian restaurant in New York City using the Zagat ratings. The possible explanatory variables include Food, Service, Decor, and East. Other variables recorded in the data set that should not be considered explanatory variables are Case (which records an ID number for each restaurant), and Restaurant (which records the name of the restaurant). Consider for a moment what a full model that included all of these explanatory variables would look like.
4. Collinearity
If one variable is a constant multiple of another variable, then they are said to be collinear. If two collinear variables are explanatory variables in a model, the second one won’t tell you anything, because it is providing redundant information. A solution would be to simply drop one of the variables from the model. Which one you drop doesn’t matter, since they are providing the same information. Here we demonstrate collinearity between Price measured in dollars and Price measured in cents. The values of the two variables aren’t the same, but they are perfectly correlated. If you already know the price in dollars, you don’t get any additional information from knowing the price in cents. Real data hardly ever lines up perfectly, so you’ll rarely have perfect collinearity. However, variables that are highly correlated will be approximately colinear. Furthermore, the colinearity does not have to be one-to-one. It might be the case that one variable is colinear with a linear combination of several other variables. This can make it much harder to figure out which variable might be appropriate to drop.
nyc %>%
mutate(Price_cents = Price / 100) %>%
summarize(cor_collinear = cor(Price, Price_cents))
5. Multicollinearity
As we add more explanatory variables to our model, it becomes more likely that we will encounter multicollinearity. A full discussion of multicollinearity and how you can work around it is beyond the scope of this course, but you should be familiar with the basic problem. The main problem with multicollinearity is that it makes the coefficient estimates unstable. This means that small changes to the values in one variable (say, changing the food rating of a few restaurants) can result in dramatic changes to the best-fit coefficients. This instability makes our results less robust. However, multicollinearity does not compromise the explanatory power of the model as a whole. The R squared values are still valid. While there are a number of approaches to diagnosing and correcting for multicollinearity, at this stage you should exercise great caution when interpreting coefficients in a model where you have highly correlated explanatory variables. If you see results that seem strange, counterintuitive, or surprising, it might be that multicollinearity is to blame.
6. Let’s practice!
Let’s get you going on these next exercises.
Parallel planes with location
We have explored models that included the quality of both food and service, as well as location, but we haven’t put these variables all into the same model. Let’s now build a parallel planes model that incorporates all three variables.
Examine the coefficients closely. Do they make sense based on what you understand about these data so far? How did the coefficients change from the previous models that you fit?
Instructions
- Use
lm() to fit a parallel planes model for Price as a function of Food, Service, and East.
mod
Call:
lm(formula = Price ~ Food + Service + East, data = nyc)
Coefficients:
(Intercept) Food Service East
-20.8155 1.4863 1.6647 0.9649
Interpretation of location coefficient
The fitted coefficients from the parallel planes model are listed below.
(Intercept) Food Service East -20.8154761 1.4862725 1.6646884 0.9648814
Which of the following statements is FALSE?
Reason about the magnitude of the East coefficient.
Possible Answers
The premium for being on the East side of 5th Avenue is just less than a dollar, after controlling for the quality of food and service.
The impact of location is relatively small, since one additional rating point of either food or service would result in a higher expected price than moving a restaurant from the West side to the East side.
The expected price of a meal on the East side is about 96% of the cost of a meal on the West side, after controlling for the quality of food and service.
Answer: 3
Impact of location
The impact of location brings us to a modeling question: should we keep this variable in our model? In a later course, you will learn how we can conduct formal hypothesis tests to help us answer that question. In this course, we will focus on the size of the effect. Is the impact of location big or small?
One way to think about this would be in terms of the practical significance. Is the value of the coefficient large enough to make a difference to your average person? The units are in dollars so in this case this question is not hard to grasp.
Another way is to examine the impact of location in the context of the variability of the other variables. We can do this by building our parallel planes in 3D and seeing how far apart they are. Are the planes close together or far apart? Does the East variable clearly separate the data into two distinct groups? Or are the points all mixed up together?
Instructions
- Use
plot_ly to draw 3D scatterplot for Price as a function of Food, Service, and East by mapping the z variable to the response and the x and y variables to the numeric explanatory variables. Use color to indicate the value of East. Place Food on the x-axis and Service on the y-axis.
- Use
add_surface() (twice) to draw two planes through the cloud of points, one for restaurants on the West side and another for restaurants on the East side. Use the objects plane0 and plane1.
# draw 3D scatterplot
p <- plot_ly(data = nyc, z = ~Price, x = ~Food, y = ~Service, opacity = 0.6) %>%
add_markers(color = ~factor(East), marker = list(size = 2))
# draw two planes
p %>%
add_surface(x = ~x, y = ~y, z = ~plane0, showscale = FALSE) %>%
add_surface(x = ~x, y = ~y, z = ~plane1, showscale = FALSE)
minimal value for n is 3, returning requested palette with 3 different levels
minimal value for n is 3, returning requested palette with 3 different levels
minimal value for n is 3, returning requested palette with 3 different levels
minimal value for n is 3, returning requested palette with 3 different levels
Full model
One variable we haven’t considered is Decor. Do people, on average, pay more for a meal in a restaurant with nicer decor? If so, does it still matter after controlling for the quality of food, service, and location?
By adding a third numeric explanatory variable to our model, we lose the ability to visualize the model in even three dimensions. Our model is now a hyperplane – or rather, parallel hyperplanes – and while we won’t go any further with the geometry, know that we can continue to add as many variables to our model as we want. As humans, our spatial visualization ability taps out after three numeric variables (maybe you could argue for four, but certainly no further), but neither the mathematical equation for the regression model, nor the formula specification for the model in R, is bothered by the higher dimensionality.
Use lm() to fit a parallel planes model for Price as a function of Food, Service, Decor, and East.
lm(Price ~ Food + Service + Decor + East, data = nyc)
Call:
lm(formula = Price ~ Food + Service + Decor + East, data = nyc)
Coefficients:
(Intercept) Food Service Decor East
-24.023800 1.538120 -0.002727 1.910087 2.068050
cor(nyc[, -2])
Case Price Food Decor Service
Case 1.0000000 -0.2221911 -0.2030358 -0.11965518 -0.2332600
Price -0.2221911 1.0000000 0.6270435 0.72435248 0.6411402
Food -0.2030358 0.6270435 1.0000000 0.50391610 0.7945248
Decor -0.1196552 0.7243525 0.5039161 1.00000000 0.6453306
Service -0.2332600 0.6411402 0.7945248 0.64533055 1.0000000
East -0.6427551 0.1866302 0.1803706 0.03574929 0.2090941
East
Case -0.64275505
Price 0.18663024
Food 0.18037061
Decor 0.03574929
Service 0.20909408
East 1.00000000
Notice the dramatic change in the value of the Service coefficient.
Which of the following interpretations is invalid?
Possible Answers
Since the quality of food, decor, and service were all strongly correlated, multicollinearity is the likely explanation.
Once we control for the quality of food, decor, and location, the additional information conveyed by service is negligible.
Service is not an important factor in determining the price of a meal.
None of the above.
Answer: 3
1. Wrap-up
Thanks for taking this course on multiple and logistic regression with us. We hope that you’ve found this course to be illuminating and useful. You learned about a variety of multiple regression models by focusing on the interplay between the mathematical, geometric, and syntactical representations of these models. You extended many of those same ideas to logistic regression, which covers the case in which we have a binary response variable. We discussed this material as a branch of descriptive statistics. That is, we focused on how the models work, how we should interpret them, and how they can be used, but we didn’t talk at all about inference. Statisticians have developed many techniques for performing inference on the parameters of these regression models. Those techniques help us answer questions about whether the effects we observe are within the realm of statistical noise, or not. Without inference, we can only state how big the effect we observed was—we can’t make any claims about whether that effect was likely the result of chance alone, or whether it represents a meaningful characterization of the underlying phenomenon. To complete your understanding, you should learn about inferential techniques for regression in another DataCamp course. It’s been my pleasure to be your instructor for this course—have a great day!
LS0tCnRpdGxlOiAiMDUgLSBDYXNlIFN0dWR5OiBJdGFsaWFuIHJlc3RhdXJhbnRzIGluIE5ZQyIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IGZhbHNlCiAgICB0b2NfZGVwdGg6IDQKICAgIGNvZGVfZm9sZGluZzogaGlkZQotLS0KCmBgYHtyLCBlY2hvID0gRkFMU0V9Cm55YyA8LSByZWFkLmNzdignL2hvbWUvY2xhL0RvY3VtZW50b3MvVml0b3IvRGF0YUNhbXAvU3RhdGlzdGljaWFuLXdpdGgtUi8vRGF0YXNldHMvbnljX3Jlc3RfcmV2aWV3cy5jc3YnKQpgYGAKCiMjICoqSXRhbGlhbiByZXN0YXVyYW50cyBpbiBOWUMqKgoKKioxLiBJdGFsaWFuIHJlc3RhdXJhbnRzIGluIE5ZQyoqCgoqKjIuIEl0YWxpYW4gcmVzdGF1cmFudHMgaW4gTllDKioKCk5vIG1hdHRlciB3aGVyZSB5b3UgYXJlLCBvciB3aGVyZSB5b3UndmUgYmVlbiwgaWYgeW91J3JlIHRha2luZyB0aGlzIGNvdXJzZSwgbXkgZ3Vlc3MgaXMgdGhhdCB5b3UndmUgYmVlbiB0byBhIHJlc3RhdXJhbnQgYmVmb3JlLiBBbmQgaWYgeW91J3JlIGluIEV1cm9wZSBvciBOb3J0aCBBbWVyaWNhLCB0aGVyZSdzIGFuIGV4Y2VsbGVudCBjaGFuY2UgdGhhdCB5b3UndmUgYmVlbiB0byBhbiBJdGFsaWFuIHJlc3RhdXJhbnQuIFRoZSBJdGFsaWFuIHJlc3RhdXJhbnRzIGluIE5ldyBZb3JrIENpdHkgYXJlIGxlZ2VuZGFyeSwgYW5kIGl0J3MgdGltZSB0byBwdXQgeW91ciBuZXdseS1kZXZlbG9wZWQgcmVncmVzc2lvbiBtb2RlbGluZyBza2lsbHMgdG8gd29yayB0byB1bmRlcnN0YW5kIGhvdyB0aGV5IG9wZXJhdGUuIFdoYXQgYXJlIHRoZSBmYWN0b3JzIHRoYXQgY29udHJpYnV0ZSB0byBhIHByaWNlIG9mIGEgbWVhbCBhdCBJdGFsaWFuIHJlc3RhdXJhbnRzIGluIE5ldyBZb3JrIENpdHk/IFdlIHdpbGwgYWRkcmVzcyB0aGlzIHF1ZXN0aW9uIHdpdGggYSBzZXJpZXMgb2YgbXVsdGlwbGUgcmVncmVzc2lvbiBtb2RlbHMuCgoqKjMuIFphZ2F0IGd1aWRlKioKClRoZSBaYWdhdCBndWlkZSBpcyBhbiBpbmZsdWVudGlhbCByZXZpZXcgb2YgcmVzdGF1cmFudHMuIFRoZXkgYXJlIG1hZGUgZmFtb3VzIGJ5IHRoZWlyIHVzZSBvZiBzZWxlY3RpdmUgcXVvdGVzIGZyb20gYWN0dWFsIGRpbmVycyB0byBidWlsZCBhIHBpdGh5IGRlc2NyaXB0aW9uIG9mIGVhY2ggcmVzdGF1cmFudC4gQnV0IHdlIHdvbid0IGJlIHdvcmtpbmcgd2l0aCB0aGUgdGV4dC4gUmF0aGVyLCB3ZSdsbCBiZSB3b3JraW5nIHdpdGggdGhlIG51bWVyaWMgcmV2aWV3cyB5b3Ugc2VlIHBvc3RlZCBoZXJlLiBFYWNoIHJlc3RhdXJhbnQgaXMgcmF0ZWQgb24gYSBzY2FsZSBvZiAwIHRvIDMwIGZvciB0aGUgcXVhbGl0eSBvZiBpdHMgZm9vZCwgZGVjb3IsIGFuZCBzZXJ2aWNlLiBUaGUgYXZlcmFnZSBwcmljZSBvZiBhIG1lYWwtLS13aGljaCBpbmNsdWRlcyBvbmUgZHJpbmsgYW5kIGEgdGlwLS0td2lsbCBiZSBvdXIgcmVzcG9uc2UgdmFyaWFibGUuIEhvdyBkbyB0aGVzZSBmYWN0b3JzIGluZmx1ZW5jZSB0aGUgYXZlcmFnZSBwcmljZSBvZiBhIG1lYWw/CgoqKjQuIEV4cGxvcmluZyB0aGUgZGF0YSoqCgpPdXIgZGF0YSBjb21lIGluIHRoZSBmb3JtIG9mIFphZ2F0IHJldmlld3MgZnJvbSAxNjggSXRhbGlhbiByZXN0YXVyYW50cyBpbiBOZXcgWW9yayBDaXR5IGZyb20gMjAwMS4gVGhlIGdsaW1wc2UoKSBmdW5jdGlvbiBjYW4gaGVscCB5b3UgZ2V0IGEgc2Vuc2Ugb2YgaG93IHRoZSB2YXJpYWJsZXMgYXJlIGVuY29kZWQgYW5kIHdoYXQgdmFsdWVzIHRoZXkgdHlwaWNhbGx5IHRha2Ugb24uIFRoZSBFYXN0IHZhcmlhYmxlIHJlY29yZHMgd2hldGhlciB0aGUgcmVzdGF1cmFudCBpcyBsb2NhdGVkIGVhc3Qgb3Igd2VzdCBvZiBGaWZ0aCBBdmVudWUsIHdoaWNoIGhpc3RvcmljYWxseSBkaXZpZGVzIHRoZSBpc2xhbmQgb2YgTWFuaGF0dGFuLgoKYGBge3J9CmdsaW1wc2UobnljKQpgYGAKCioqNS4gRURBKioKCkJlZm9yZSB3ZSBjYW4gc2Vuc2libHkgYnVpbGQgbW9kZWxzLCB3ZSBzaG91bGQgc3BlbmQgc29tZSB0aW1lIGV4cGxvcmluZyB0aGUgZGF0YS4gSG93IGFyZSB0aGUgdmFyaWFibGVzIGRpc3RyaWJ1dGVkPyBIb3cgYXJlIHRoZXkgcmVsYXRlZCB0byBvbmUgYW5vdGhlcj8gV2hhdCBwYXR0ZXJucyBhcmUgcHJlc2VudD8gVGhlIHBhaXJzKCkgZnVuY3Rpb24gY2FuIGhlbHAgdXMgZXhwbG9yZSB0aGVzZSByZWxhdGlvbnNoaXBzIHZpc3VhbGx5LiBJdCBzaG93cyBhIGdyaWQgb2Ygc2NhdHRlcnBsb3RzIGZvciBlYWNoIHBhaXIgb2YgdmFyaWFibGVzIGluIHRoZSBueWMgZGF0YSBmcmFtZS4gSXQncyBlYXN5IHRvIHNlZSB0aGF0LCBmb3IgZXhhbXBsZSwgUHJpY2UgYW5kIERlY29yIGFyZSBzdHJvbmdseSBjb3JyZWxhdGVkLCB3aGlsZSBDYXNlIGFuZCBGb29kIGFyZSB1bmNvcnJlbGF0ZWQuCgpgYGB7cn0KbnljJFJlc3RhdXJhbnQgPC0gZmFjdG9yKG55YyRSZXN0YXVyYW50KQpwYWlycyhueWMpCmBgYAoKKio2LiBMZXQncyBwcmFjdGljZSEqKgoKTm93IGl0J3MgdGltZSBmb3IgeW91IHRvIHNpbmsgeW91ciB0ZWV0aCBpbnRvIHRoZXNlIGRhdGEuCgojIyMgKipFeHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzKioKCk11bHRpcGxlIHJlZ3Jlc3Npb24gY2FuIGJlIGFuIGVmZmVjdGl2ZSB0ZWNobmlxdWUgZm9yIHVuZGVyc3RhbmRpbmcgaG93IGEgcmVzcG9uc2UgdmFyaWFibGUgY2hhbmdlcyBhcyBhIHJlc3VsdCBvZiBjaGFuZ2VzIHRvIG1vcmUgdGhhbiBvbmUgZXhwbGFuYXRvcnkgdmFyaWFibGUuIEJ1dCBpdCBpcyBub3QgbWFnaWMgLS0gdW5kZXJzdGFuZGluZyB0aGUgcmVsYXRpb25zaGlwcyBhbW9uZyB0aGUgZXhwbGFuYXRvcnkgdmFyaWFibGVzIGlzIGFsc28gbmVjZXNzYXJ5LCBhbmQgd2lsbCBoZWxwIHVzIGJ1aWxkIGEgYmV0dGVyIG1vZGVsLiBUaGlzIHByb2Nlc3MgaXMgb2Z0ZW4gY2FsbGVkIFtleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9FeHBsb3JhdG9yeV9kYXRhX2FuYWx5c2lzKSAoRURBKSBhbmQgaXMgY292ZXJlZCBpbiBhbm90aGVyIERhdGFDYW1wIGNvdXJzZS4KCk9uZSBxdWljayB0ZWNobmlxdWUgZm9yIGp1bXAtc3RhcnRpbmcgRURBIGlzIHRvIGV4YW1pbmUgYWxsIG9mIHRoZSBwYWlyd2lzZSBzY2F0dGVycGxvdHMgaW4geW91ciBkYXRhLiBUaGlzIGNhbiBiZSBhY2hpZXZlZCB1c2luZyB0aGUgYHBhaXJzKClgIGZ1bmN0aW9uLiBMb29rIGZvciB2YXJpYWJsZXMgaW4gdGhlIGBueWNgIGRhdGEgc2V0IHRoYXQgYXJlIHN0cm9uZ2x5IGNvcnJlbGF0ZWQsIGFzIHRob3NlIHJlbGF0aW9uc2hpcHMgd2lsbCBoZWxwIHVzIGNoZWNrIGZvciBbbXVsdGljb2xsaW5lYXJpdHldKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL011bHRpY29sbGluZWFyaXR5KSBsYXRlciBvbi4KCldoaWNoIHBhaXJzIG9mIHZhcmlhYmxlcyBhcHBlYXIgdG8gYmUgc3Ryb25nbHkgY29ycmVsYXRlZD8KCmBgYHtyfQpjb3IobnljWywgLWMoMildKQpgYGAKCkE6IEZvb2QgYW5kIFNlcnZpY2UKCiMjIyAqKlNMUiBtb2RlbHMqKgoKQmFzZWQgb24geW91ciBrbm93bGVkZ2Ugb2YgdGhlIHJlc3RhdXJhbnQgaW5kdXN0cnksIGRvIHlvdSB0aGluayB0aGF0IHRoZSBxdWFsaXR5IG9mIHRoZSBmb29kIGluIGEgcmVzdGF1cmFudCBpcyBhbiBpbXBvcnRhbnQgZGV0ZXJtaW5hbnQgb2YgdGhlIHByaWNlIG9mIGEgbWVhbCBhdCB0aGF0IHJlc3RhdXJhbnQ/IEl0IHdvdWxkIGJlIGhhcmQgdG8gaW1hZ2luZSB0aGF0IGl0IHdhc24ndC4gV2UnbGwgc3RhcnQgb3VyIG1vZGVsaW5nIHByb2Nlc3MgYnkgcGxvdHRpbmcgYW5kIGZpdHRpbmcgYSBtb2RlbCBmb3IgYFByaWNlYCBhcyBhIGZ1bmN0aW9uIG9mIGBGb29kYC4KCk9uIHlvdXIgb3duLCBpbnRlcnByZXQgdGhlc2UgY29lZmZpY2llbnRzIGFuZCBleGFtaW5lIHRoZSBmaXQgb2YgdGhlIG1vZGVsLiBXaGF0IGRvZXMgdGhlIGNvZWZmaWNpZW50IG9mIGBGb29kYCBtZWFuIGluIHBsYWluIEVuZ2xpc2g/ICJFYWNoIGFkZGl0aW9uYWwgcmF0aW5nIHBvaW50IG9mIGZvb2QgcXVhbGl0eSBpcyBhc3NvY2lhdGVkIHdpdGggYS4uLiIKCioqSW5zdHJ1Y3Rpb25zKioKCi0gVXNlIGBnZ3Bsb3RgIHRvIG1ha2UgYSBzY2F0dGVyIHBsb3QgZm9yIGBQcmljZWAgYXMgYSBmdW5jdGlvbiBvZiBgRm9vZGAuCi0gVXNlIGBsbSgpYCB0byBmaXQgYSBzaW1wbGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgZm9yIGBQcmljZWAgYXMgYSBmdW5jdGlvbiBvZiBgRm9vZGAuCgpgYGB7cn0KIyBQcmljZSBieSBGb29kIHBsb3QKZ2dwbG90KGRhdGEgPSBueWMsIGFlcyh4ID0gRm9vZCwgeSA9IFByaWNlKSkgKwogIGdlb21fcG9pbnQoKQoKIyBQcmljZSBieSBGb29kIG1vZGVsCmxtKFByaWNlIH4gRm9vZCwgZGF0YSA9IG55YykKYGBgCgpXaGF0IGRvZXMgdGhlIHNpbXBsZSBsaW5lYXIgbW9kZWwgc2F5IGFib3V0IGhvdyBmb29kIHF1YWxpdHkgYWZmZWN0cyBwcmljZT8KCiMjICoqSW5jb3Jwb3JhdGluZyBhbm90aGVyIHZhcmlhYmxlKioKCioqMS4gSW5jb3Jwb3JhdGluZyBhbm90aGVyIHZhcmlhYmxlKioKCioqMi4gRmlmdGggQXZlbnVlKioKCkZpZnRoIEF2ZW51ZSBpcyBvbmUgdGhlIG1vc3Qgd2VsbC1rbm93biBzdHJlZXRzIGluIHRoZSB3b3JsZCwgcmVub3duZWQgZm9yIGl0cyBmbGFnc2hpcCBzdG9yZXMgZm9yIHNob3BwaW5nLCBsYW5kbWFyayBob3RlbHMsIGFuZCBpbnRlcm5hdGlvbmFsbHktcmVjb2duaXplZCBzaXRlcy4gQSB3YWxrIGRvd24gNXRoIEF2ZW51ZSBmcm9tIENlbnRyYWwgUGFyayB0byBXYXNoaW5ndG9uIFNxdWFyZSBQYXJrIHdvdWxkIHRha2UgeW91IHBhc3QgdGhlIFBsYXphIEhvdGVsLCBUcnVtcCBUb3dlciwgU2FrcyBGaWZ0aCBBdmVudWUsIHRoZSBOZXcgWW9yayBQdWJsaWMgTGlicmFyeSwgdGhlIEVtcGlyZSBTdGF0ZSBCdWlsZGluZywgYW5kIHRoZSBGbGF0aXJvbiBidWlsZGluZy4KCioqMy4gQ1VOWSoqCgpJdCB3b3VsZCBhbHNvIHRha2UgeW91IHBhc3QgdGhlIEdyYWR1YXRlIENlbnRlciBvZiB0aGUgQ2l0eSBVbml2ZXJzaXR5IG9mIE5ldyBZb3JrLCB3aGVyZSBJIHN0dWRpZWQgZm9yIG15IGRvY3RvcmFsIGRlZ3JlZS4gR29vZCB0aW1lcyEKCioqNC4gRGl2aWRpbmcgdGhlIENpdHkqKgoKNXRoIEF2ZW51ZSBkaXZpZGVzIHRoZSBpc2xhbmQgb2YgTWFuaGF0dGFuIHZlcnRpY2FsbHkuIFRoZSBjaXR5J3MgZWFzdCBzaWRlIGhhcyBoaXN0b3JpY2FsbHkgYmVlbiBob21lIHRvIGV4cGVuc2l2ZSByZXNpZGVuY2VzIGFuZCBvcHVsZW50IGF0dHJhY3Rpb25zLiBNYXliZSBldmVyeXRoaW5nIGlzIG1vcmUgZXhwZW5zaXZlIG9uIHRoZSBFYXN0IHNpZGUuIE1heWJlIGV2ZW4gZm9vZCBpcyBtb3JlIGV4cGVuc2l2ZSBvbiB0aGUgZWFzdCBzaWRlLiBEbyBJdGFsaWFuIHJlc3RhdXJhbnRzIGxvY2F0ZWQgb24gdGhlIGVhc3Qgc2lkZSBvZiA1dGggQXZlbnVlIHRlbmQgdG8gY2hhcmdlIG1vcmU/IEhvdyBtdWNoIG1vcmU/CgoqKjUuIFRoZSBwcmljZSBvZiBsb2NhdGlvbioqCgpJdCdzIGNlcnRhaW5seSB0cnVlIHRoYXQgdGhlIGF2ZXJhZ2UgcHJpY2Ugb2YgYSBtZWFsIGZvciByZXN0YXVyYW50cyBsb2NhdGVkIG9uIHRoZSBlYXN0IHNpZGUgb2YgTWFuaGF0dGFuIHdhcyBoaWdoZXIgdGhhbiBpdCB3YXMgZm9yIHJlc3RhdXJhbnRzIG9uIHRoZSB3ZXN0IHNpZGUuIFRoZSB0YWJsZSBhYm92ZSBzaG93cyB0aGF0IHRoZXkgY2hhcmdlZCBhYm91dCAkMyBwb2ludCA1OCBtb3JlLCBvbiBhdmVyYWdlLiBCdXQgZG9lcyB0aGlzIGZpZ3VyZSByZWFsbHkgcmVwcmVzZW50IHRoZSBwcmVtaXVtIGZvciBiZWluZyBvbiB0aGUgZWFzdCBzaWRlPyBDb3VsZCBpdCBiZSB0aGUgY2FzZSB0aGF0IHRoZSByZXN0YXVyYW50cyBvbiB0aGUgZWFzdCBzaWRlIGFsc28gaGFkIGJldHRlciBmb29kLCBhbmQgdGhhdCBpcyB3aGF0IHdhcyBkcml2aW5nIHRoZSBpbmNyZWFzZSBpbiBwcmljZT8gWW91J2xsIGV4cGxvcmUgdGhpcyBxdWVzdGlvbiBpbiB0aGUgZXhlcmNpc2VzLgoKYGBge3J9Cm55YyAlPiUgCiAgZ3JvdXBfYnkoRWFzdCkgJT4lIAogIHN1bW1hcml6ZShtZWFuX3ByaWNlID0gbWVhbihQcmljZSkpCmBgYAoKKio2LiBTZXJ2aWNlKioKCkFub3RoZXIgaW1wb3J0YW50IGNvbnNpZGVyYXRpb24gaW4gZGluaW5nIG91dCBpcyB0aGUgcXVhbGl0eSBvZiB0aGUgc2VydmljZS4gQXJlIHBlb3BsZSB3aWxsaW5nIHRvIHBheSBtb3JlIGZvciBoaWdoZXIgcXVhbGl0eSBzZXJ2aWNlLCBldmVuIGlmIHRoZSBmb29kIGRvZXNuJ3QgdGFzdGUgYW55IGJldHRlcj8gSG93IG11Y2ggbW9yZT8gSG93IGRvZXMgdGhlIGF2ZXJhZ2UgcHJpY2Ugb2YgbWVhbCB2YXJ5IHdpdGggcmVzcGVjdCB0byB0aGUgcXVhbGl0eSBvZiB0aGUgZm9vZCBhbmQgdGhlIHNlcnZpY2U/IEl0J3MgdXAgdG8geW91IHRvIGZpZ3VyZSBpdCBvdXQuCgoqKjcuIExldCdzIHByYWN0aWNlISoqCgpUaGVzZSBuZXh0IGV4ZXJjaXNlcyB3aWxsIGFsbG93IHlvdSB0byBkZWx2ZSBpbnRvIHRoZXNlIHF1ZXN0aW9ucy4KCiMjIyAqKlBhcmFsbGVsIGxpbmVzIHdpdGggbG9jYXRpb24qKgoKSW4gcmVhbCBlc3RhdGUsIGEgY29tbW9uIG1hbnRyYSBpcyB0aGF0IHRoZSB0aHJlZSBtb3N0IGltcG9ydGFudCBmYWN0b3JzIGluIGRldGVybWluaW5nIHRoZSBwcmljZSBvZiBhIHByb3BlcnR5IGFyZSAibG9jYXRpb24sIGxvY2F0aW9uLCBhbmQgbG9jYXRpb24uIiBJZiBsb2NhdGlvbiBkcml2ZXMgdXAgcHJvcGVydHkgdmFsdWVzIGFuZCByZW50cywgdGhlbiB3ZSBtaWdodCBpbWFnaW5lIHRoYXQgbG9jYXRpb24gd291bGQgaW5jcmVhc2UgYSByZXN0YXVyYW50J3MgY29zdHMsIHdoaWNoIHdvdWxkIHJlc3VsdCBpbiB0aGVtIGhhdmluZyBoaWdoZXIgcHJpY2VzLiBJbiBtYW55IHBhcnRzIG9mIE5ldyBZb3JrLCB0aGUgZWFzdCBzaWRlIChlYXN0IG9mIDV0aCBBdmVudWUpIGlzIG1vcmUgZGV2ZWxvcGVkIGFuZCBwZXJoYXBzIG1vcmUgZXhwZW5zaXZlLiBbVGhpcyBpcyBpbmNyZWFzaW5nbHkgbGVzcyB0cnVlLCBidXQgd2FzIG1vcmUgdHJ1ZSBhdCB0aGUgdGltZSB0aGVzZSBkYXRhIHdlcmUgY29sbGVjdGVkLl0KCkxldCdzIGV4cGFuZCBvdXIgbW9kZWwgaW50byBhIHBhcmFsbGVsIHNsb3BlcyBtb2RlbCBieSBpbmNsdWRpbmcgdGhlIGBFYXN0YCB2YXJpYWJsZSBpbiBhZGRpdGlvbiB0byBgRm9vZGAuCgpVc2UgYGxtKClgIHRvIGZpdCBhIHBhcmFsbGVsIHNsb3BlcyBtb2RlbCBmb3IgYFByaWNlYCBhcyBhIGZ1bmN0aW9uIG9mIGBGb29kYCBhbmQgYEVhc3RgLiBJbnRlcnByZXQgdGhlIGNvZWZmaWNpZW50cyBhbmQgdGhlIGZpdCBvZiB0aGUgbW9kZWwuIENhbiB5b3UgZXhwbGFpbiB0aGUgbWVhbmluZyBvZiB0aGUgY29lZmZpY2llbnQgb24gYEVhc3RgIGluIHNpbXBsZSB0ZXJtcz8gRGlkIHRoZSBjb2VmZmljaWVudCBvbiBgRm9vZGAgY2hhbmdlIGZyb20gdGhlIHByZXZpb3VzIG1vZGVsPyBJZiBzbywgd2h5PyBEaWQgaXQgY2hhbmdlIGJ5IGEgbG90IG9yIGp1c3QgYSBsaXR0bGU/CgpJZGVudGlmeSB0aGUgc3RhdGVtZW50IHRoYXQgaXMgKkZBTFNFKjoKCioqUG9zc2libGUgQW5zd2VycyoqCgoxLiBFYWNoIGFkZGl0aW9uYWwgcmF0aW5nIHBvaW50IG9mIGZvb2QgcXVhbGl0eSBpcyBhc3NvY2lhdGVkIHdpdGggYSAkMi44OCBpbmNyZWFzZSBpbiB0aGUgZXhwZWN0ZWQgcHJpY2Ugb2YgbWVhbCwgYWZ0ZXIgY29udHJvbGxpbmcgZm9yIGxvY2F0aW9uLgoKMi4gVGhlIHByZW1pdW0gZm9yIGFuIEl0YWxpYW4gcmVzdGF1cmFudCBpbiBOWUMgYXNzb2NpYXRlZCB3aXRoIGJlaW5nIG9uIHRoZSBlYXN0IHNpZGUgb2YgNXRoIEF2ZW51ZSBpcyAkMS40NiwgYWZ0ZXIgY29udHJvbGxpbmcgZm9yIHRoZSBxdWFsaXR5IG9mIHRoZSBmb29kLgoKMy4gVGhlIGNoYW5nZSBpbiB0aGUgY29lZmZpY2llbnQgb2YgZm9vZCBmcm9tIFwkMi45NCBpbiB0aGUgc2ltcGxlIGxpbmVhciBtb2RlbCB0byAkMi44OCBpbiB0aGlzIG1vZGVsIGhhcyBwcm9mb3VuZCBwcmFjdGljYWwgaW1wbGljYXRpb25zIGZvciByZXN0YXVyYW50IG93bmVycy4KCmBgYHtyfQpsbShQcmljZSB+IEZvb2QsIGRhdGEgPSBueWMpCmxtKFByaWNlIH4gRm9vZCArIEVhc3QsIGRhdGEgPSBueWMpCmBgYAoKQTogMwoKIyMjICoqQSBwbGFuZSBpbiAzRCoqCgpPbmUgcmVhc29uIHRoYXQgbWFueSBwZW9wbGUgZ28gdG8gYSByZXN0YXVyYW504oCUYXBhcnQgZnJvbSB0aGUgZm9vZOKAlGlzIHRoYXQgdGhleSBkb24ndCBoYXZlIHRvIGNvb2sgb3IgY2xlYW4gdXAuIE1hbnkgcGVvcGxlIGFwcHJlY2lhdGUgdGhlIGV4cGVyaWVuY2Ugb2YgYmVpbmcgd2FpdGVkIHVwb24sIGFuZCB3ZSBjYW4gYWxsIGFncmVlIHRoYXQgdGhlIHF1YWxpdHkgb2YgdGhlIHNlcnZpY2UgYXQgcmVzdGF1cmFudHMgdmFyaWVzIHdpZGVseS4gQXJlIHBlb3BsZSB3aWxsaW5nIHRvIHBheSBtb3JlIGZvciBiZXR0ZXIgcmVzdGF1cmFudCBgU2VydmljZWA/IE1vcmUgaW50ZXJlc3RpbmdseSwgYXJlIHRoZXkgd2lsbGluZyB0byBwYXkgbW9yZSBmb3IgYmV0dGVyIHNlcnZpY2UsIGFmdGVyIGNvbnRyb2xsaW5nIGZvciB0aGUgcXVhbGl0eSBvZiB0aGUgZm9vZD8KCk11bHRpcGxlIHJlZ3Jlc3Npb24gZ2l2ZXMgdXMgYSB3YXkgdG8gcmVhc29uIGFib3V0IHRoZXNlIHF1ZXN0aW9ucy4gRml0IHRoZSBtb2RlbCB3aXRoIGBGb29kYCBhbmQgYFNlcnZpY2VgIGFuZCBpbnRlcnByZXQgdGhlIGNvZWZmaWNpZW50cyBhbmQgZml0LiBEaWQgdGhlIGNvZWZmaWNpZW50IG9uIGBGb29kYCBjaGFuZ2UgZnJvbSB0aGUgcHJldmlvdXMgbW9kZWw/IFdoYXQgZG8gdGhlIGNvZWZmaWNpZW50cyBvbiBgRm9vZGAgYW5kIGBTZXJ2aWNlYCB0ZWxsIHlvdSBhYm91dCBob3cgdGhlc2UgcmVzdGF1cmFudHMgc2V0IHByaWNlcz8KCk5leHQsIGxldCdzIHZpc3VhbGx5IGFzc2VzcyBvdXIgbW9kZWwgdXNpbmcgYHBsb3RseWAuIFRoZSBgeGAgYW5kIGB5YCB2ZWN0b3JzLCBhcyB3ZWxsIGFzIHRoZSBgcGxhbmVgIG1hdHJpeCwgaGF2ZSBiZWVuIGNyZWF0ZWQgZm9yIHlvdS4KCmBgYHtyLCBlY2hvID0gRkFMU0V9Cm1vZCA8LSBsbShQcmljZSB+IEZvb2QgKyBTZXJ2aWNlLCBkYXRhID0gbnljKQp4IDwtIHNlcV9yYW5nZShueWMkRm9vZCwgbiA9IDUwKQp5IDwtIHNlcV9yYW5nZShueWMkU2VydmljZSwgbiA9IDUwKQpwbGFuZSA8LSBtYXRyaXgobnJvdyA9IDUwLCBuY29sID0gNTApCmZvciAoaSBpbiBzZXFfYWxvbmcoeCkpIHsKICBwbGFuZVtpLCBdIDwtIHByZWRpY3QobW9kLCBuZXdkYXRhID0gZGF0YS5mcmFtZShGb29kID0geCwgU2VydmljZSA9IHlbaV0pKQp9IApgYGAKCioqSW5zdHJ1Y3Rpb25zKioKCiAtIFVzZSBgbG0oKWAgdG8gZml0IGEgbXVsdGlwbGUgcmVncmVzc2lvbiBtb2RlbCBmb3IgYFByaWNlYCBhcyBhIGZ1bmN0aW9uIG9mIGBGb29kYCBhbmQgYFNlcnZpY2VgLgotIFVzZSBgcGxvdF9seWAgdG8gZHJhdyAzRCBzY2F0dGVycGxvdCBmb3IgYFByaWNlYCBhcyBhIGZ1bmN0aW9uIG9mIGBGb29kYCBhbmQgYFNlcnZpY2VgIGJ5IG1hcHBpbmcgdGhlIGB6YCB2YXJpYWJsZSB0byB0aGUgcmVzcG9uc2UgYW5kIHRoZSBgeGAgYW5kIGB5YCB2YXJpYWJsZXMgdG8gdGhlIGV4cGxhbmF0b3J5IHZhcmlhYmxlcy4gUGxhY2UgdGhlIGZvb2QgcXVhbGl0eSBvbiB0aGUgeC1heGlzIGFuZCBzZXJ2aWNlIHJhdGluZyBvbiB0aGUgeS1heGlzLgotIFVzZSBgYWRkX3N1cmZhY2UoKWAgdG8gZHJhdyBhIHBsYW5lIHRocm91Z2ggdGhlIGNsb3VkIG9mIHBvaW50cyB1c2luZyB0aGUgb2JqZWN0IGBwbGFuZWAuCgpgYGB7cn0KIyBmaXQgbW9kZWwKbG0oUHJpY2UgfiBGb29kICsgU2VydmljZSwgZGF0YSA9IG55YykKCiMgZHJhdyAzRCBzY2F0dGVycGxvdApwIDwtIHBsb3RfbHkoZGF0YSA9IG55YywgeiA9IH5QcmljZSwgeCA9IH5Gb29kLCB5ID0gflNlcnZpY2UsIG9wYWNpdHkgPSAwLjYpICU+JQogIGFkZF9tYXJrZXJzKG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDIpKSAKCiMgZHJhdyBhIHBsYW5lCnAgJT4lCiAgYWRkX3N1cmZhY2UoeCA9IH54LCB5ID0gfnksIHogPSB+cGxhbmUsIHNob3dzY2FsZSA9IEZBTFNFKSAKYGBgCgojIyAqKkhpZ2hlciBkaW1lbnNpb25zKioKCioqMS4gSGlnaGVyIGRpbWVuc2lvbnMqKgoKKioyLiBEZWNvcioqCgpUaGUgbGFzdCBjcml0ZXJpYSBmb3IgdGhlIFphZ2F0IHJldmlldyBpcyBkZWNvci4gVGhpcyByZWZlcnMgdG8gdGhlIHZpc3VhbCBwcmVzZW50YXRpb24gb2YgdGhlIHJlc3RhdXJhbnQ6IHRoZSBmdXJuaXR1cmUsIHRoZSB3YWxsIGFkb3JubWVudHMsIGFuZCB0aGUgb3ZlcmFsbCBhbWJpZW5jZS4gQ2xlYXJseSwgcmVzdGF1cmFudHMgdmFyeSB3aWRlbHkgaW4gdGhlIHF1YWxpdHkgb2YgdGhlaXIgZGVjb3IuIEJ1dCBob3cgZG9lcyB0aGUgcGVyY2VpdmVkIHF1YWxpdHkgb2YgZGVjb3IgdmFyeSB3aXRoIHRoZSBwcmljZSBvZiBhIG1lYWw/IEFuZCBob3cgaXMgdGhlIGVmZmVjdCBtb2RlcmF0ZWQgYnkgdGhlIHF1YWxpdHkgb2YgZm9vZCBhbmQgc2VydmljZT8KCioqMy4gQnVpbGRpbmcgYSBmdWxsIG1vZGVsKioKCkluIHdoYXQgZm9sbG93cywgeW91IHdpbGwgYnVpbGQgbW9yZSBjb21wbGV4IG1vZGVscyBmb3IgdGhlIHByaWNlIG9mIGEgbWVhbCBhdCBhbiBJdGFsaWFuIHJlc3RhdXJhbnQgaW4gTmV3IFlvcmsgQ2l0eSB1c2luZyB0aGUgWmFnYXQgcmF0aW5ncy4gVGhlIHBvc3NpYmxlIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyBpbmNsdWRlIEZvb2QsIFNlcnZpY2UsIERlY29yLCBhbmQgRWFzdC4gT3RoZXIgdmFyaWFibGVzIHJlY29yZGVkIGluIHRoZSBkYXRhIHNldCB0aGF0IHNob3VsZCBub3QgYmUgY29uc2lkZXJlZCBleHBsYW5hdG9yeSB2YXJpYWJsZXMgYXJlIENhc2UgKHdoaWNoIHJlY29yZHMgYW4gSUQgbnVtYmVyIGZvciBlYWNoIHJlc3RhdXJhbnQpLCBhbmQgUmVzdGF1cmFudCAod2hpY2ggcmVjb3JkcyB0aGUgbmFtZSBvZiB0aGUgcmVzdGF1cmFudCkuIENvbnNpZGVyIGZvciBhIG1vbWVudCB3aGF0IGEgZnVsbCBtb2RlbCB0aGF0IGluY2x1ZGVkIGFsbCBvZiB0aGVzZSBleHBsYW5hdG9yeSB2YXJpYWJsZXMgd291bGQgbG9vayBsaWtlLgoKKio0LiBDb2xsaW5lYXJpdHkqKgoKSWYgb25lIHZhcmlhYmxlIGlzIGEgY29uc3RhbnQgbXVsdGlwbGUgb2YgYW5vdGhlciB2YXJpYWJsZSwgdGhlbiB0aGV5IGFyZSBzYWlkIHRvIGJlIGNvbGxpbmVhci4gSWYgdHdvIGNvbGxpbmVhciB2YXJpYWJsZXMgYXJlIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyBpbiBhIG1vZGVsLCB0aGUgc2Vjb25kIG9uZSB3b24ndCB0ZWxsIHlvdSBhbnl0aGluZywgYmVjYXVzZSBpdCBpcyBwcm92aWRpbmcgcmVkdW5kYW50IGluZm9ybWF0aW9uLiBBIHNvbHV0aW9uIHdvdWxkIGJlIHRvIHNpbXBseSBkcm9wIG9uZSBvZiB0aGUgdmFyaWFibGVzIGZyb20gdGhlIG1vZGVsLiBXaGljaCBvbmUgeW91IGRyb3AgZG9lc24ndCBtYXR0ZXIsIHNpbmNlIHRoZXkgYXJlIHByb3ZpZGluZyB0aGUgc2FtZSBpbmZvcm1hdGlvbi4gSGVyZSB3ZSBkZW1vbnN0cmF0ZSBjb2xsaW5lYXJpdHkgYmV0d2VlbiBQcmljZSBtZWFzdXJlZCBpbiBkb2xsYXJzIGFuZCBQcmljZSBtZWFzdXJlZCBpbiBjZW50cy4gVGhlIHZhbHVlcyBvZiB0aGUgdHdvIHZhcmlhYmxlcyBhcmVuJ3QgdGhlIHNhbWUsIGJ1dCB0aGV5IGFyZSBwZXJmZWN0bHkgY29ycmVsYXRlZC4gSWYgeW91IGFscmVhZHkga25vdyB0aGUgcHJpY2UgaW4gZG9sbGFycywgeW91IGRvbid0IGdldCBhbnkgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBmcm9tIGtub3dpbmcgdGhlIHByaWNlIGluIGNlbnRzLiBSZWFsIGRhdGEgaGFyZGx5IGV2ZXIgbGluZXMgdXAgcGVyZmVjdGx5LCBzbyB5b3UnbGwgcmFyZWx5IGhhdmUgcGVyZmVjdCBjb2xsaW5lYXJpdHkuIEhvd2V2ZXIsIHZhcmlhYmxlcyB0aGF0IGFyZSBoaWdobHkgY29ycmVsYXRlZCB3aWxsIGJlIGFwcHJveGltYXRlbHkgY29saW5lYXIuIEZ1cnRoZXJtb3JlLCB0aGUgY29saW5lYXJpdHkgZG9lcyBub3QgaGF2ZSB0byBiZSBvbmUtdG8tb25lLiBJdCBtaWdodCBiZSB0aGUgY2FzZSB0aGF0IG9uZSB2YXJpYWJsZSBpcyBjb2xpbmVhciB3aXRoIGEgbGluZWFyIGNvbWJpbmF0aW9uIG9mIHNldmVyYWwgb3RoZXIgdmFyaWFibGVzLiBUaGlzIGNhbiBtYWtlIGl0IG11Y2ggaGFyZGVyIHRvIGZpZ3VyZSBvdXQgd2hpY2ggdmFyaWFibGUgbWlnaHQgYmUgYXBwcm9wcmlhdGUgdG8gZHJvcC4KCmBgYHtyfQpueWMgJT4lIAogIG11dGF0ZShQcmljZV9jZW50cyA9IFByaWNlIC8gMTAwKSAlPiUgCiAgc3VtbWFyaXplKGNvcl9jb2xsaW5lYXIgPSBjb3IoUHJpY2UsIFByaWNlX2NlbnRzKSkKYGBgCgoqKjUuIE11bHRpY29sbGluZWFyaXR5KioKCkFzIHdlIGFkZCBtb3JlIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyB0byBvdXIgbW9kZWwsIGl0IGJlY29tZXMgbW9yZSBsaWtlbHkgdGhhdCB3ZSB3aWxsIGVuY291bnRlciBtdWx0aWNvbGxpbmVhcml0eS4gQSBmdWxsIGRpc2N1c3Npb24gb2YgbXVsdGljb2xsaW5lYXJpdHkgYW5kIGhvdyB5b3UgY2FuIHdvcmsgYXJvdW5kIGl0IGlzIGJleW9uZCB0aGUgc2NvcGUgb2YgdGhpcyBjb3Vyc2UsIGJ1dCB5b3Ugc2hvdWxkIGJlIGZhbWlsaWFyIHdpdGggdGhlIGJhc2ljIHByb2JsZW0uIFRoZSBtYWluIHByb2JsZW0gd2l0aCBtdWx0aWNvbGxpbmVhcml0eSBpcyB0aGF0IGl0IG1ha2VzIHRoZSBjb2VmZmljaWVudCBlc3RpbWF0ZXMgdW5zdGFibGUuIFRoaXMgbWVhbnMgdGhhdCBzbWFsbCBjaGFuZ2VzIHRvIHRoZSB2YWx1ZXMgaW4gb25lIHZhcmlhYmxlIChzYXksIGNoYW5naW5nIHRoZSBmb29kIHJhdGluZyBvZiBhIGZldyByZXN0YXVyYW50cykgY2FuIHJlc3VsdCBpbiBkcmFtYXRpYyBjaGFuZ2VzIHRvIHRoZSBiZXN0LWZpdCBjb2VmZmljaWVudHMuIFRoaXMgaW5zdGFiaWxpdHkgbWFrZXMgb3VyIHJlc3VsdHMgbGVzcyByb2J1c3QuIEhvd2V2ZXIsIG11bHRpY29sbGluZWFyaXR5IGRvZXMgbm90IGNvbXByb21pc2UgdGhlIGV4cGxhbmF0b3J5IHBvd2VyIG9mIHRoZSBtb2RlbCBhcyBhIHdob2xlLiBUaGUgUiBzcXVhcmVkIHZhbHVlcyBhcmUgc3RpbGwgdmFsaWQuIFdoaWxlIHRoZXJlIGFyZSBhIG51bWJlciBvZiBhcHByb2FjaGVzIHRvIGRpYWdub3NpbmcgYW5kIGNvcnJlY3RpbmcgZm9yIG11bHRpY29sbGluZWFyaXR5LCBhdCB0aGlzIHN0YWdlIHlvdSBzaG91bGQgZXhlcmNpc2UgZ3JlYXQgY2F1dGlvbiB3aGVuIGludGVycHJldGluZyBjb2VmZmljaWVudHMgaW4gYSBtb2RlbCB3aGVyZSB5b3UgaGF2ZSBoaWdobHkgY29ycmVsYXRlZCBleHBsYW5hdG9yeSB2YXJpYWJsZXMuIElmIHlvdSBzZWUgcmVzdWx0cyB0aGF0IHNlZW0gc3RyYW5nZSwgY291bnRlcmludHVpdGl2ZSwgb3Igc3VycHJpc2luZywgaXQgbWlnaHQgYmUgdGhhdCBtdWx0aWNvbGxpbmVhcml0eSBpcyB0byBibGFtZS4KCioqNi4gTGV0J3MgcHJhY3RpY2UhKioKCkxldCdzIGdldCB5b3UgZ29pbmcgb24gdGhlc2UgbmV4dCBleGVyY2lzZXMuCgojIyMgKipQYXJhbGxlbCBwbGFuZXMgd2l0aCBsb2NhdGlvbioqCgpXZSBoYXZlIGV4cGxvcmVkIG1vZGVscyB0aGF0IGluY2x1ZGVkIHRoZSBxdWFsaXR5IG9mIGJvdGggZm9vZCBhbmQgc2VydmljZSwgYXMgd2VsbCBhcyBsb2NhdGlvbiwgYnV0IHdlIGhhdmVuJ3QgcHV0IHRoZXNlIHZhcmlhYmxlcyBhbGwgaW50byB0aGUgc2FtZSBtb2RlbC4gTGV0J3Mgbm93IGJ1aWxkIGEgcGFyYWxsZWwgcGxhbmVzIG1vZGVsIHRoYXQgaW5jb3Jwb3JhdGVzIGFsbCB0aHJlZSB2YXJpYWJsZXMuCgpFeGFtaW5lIHRoZSBjb2VmZmljaWVudHMgY2xvc2VseS4gRG8gdGhleSBtYWtlIHNlbnNlIGJhc2VkIG9uIHdoYXQgeW91IHVuZGVyc3RhbmQgYWJvdXQgdGhlc2UgZGF0YSBzbyBmYXI/IEhvdyBkaWQgdGhlIGNvZWZmaWNpZW50cyBjaGFuZ2UgZnJvbSB0aGUgcHJldmlvdXMgbW9kZWxzIHRoYXQgeW91IGZpdD8KCioqSW5zdHJ1Y3Rpb25zKioKCi0gVXNlIGBsbSgpYCB0byBmaXQgYSBwYXJhbGxlbCBwbGFuZXMgbW9kZWwgZm9yIGBQcmljZWAgYXMgYSBmdW5jdGlvbiBvZiBgRm9vZGAsIGBTZXJ2aWNlYCwgYW5kIGBFYXN0YC4KCmBgYHtyfQojIFByaWNlIGJ5IEZvb2QgYW5kIFNlcnZpY2UgYW5kIEVhc3QKbW9kIDwtIGxtKFByaWNlIH4gRm9vZCArIFNlcnZpY2UgKyBFYXN0LCBkYXRhID0gbnljKQptb2QKYGBgCgojIyMgKipJbnRlcnByZXRhdGlvbiBvZiBsb2NhdGlvbiBjb2VmZmljaWVudCoqCgpUaGUgZml0dGVkIGNvZWZmaWNpZW50cyBmcm9tIHRoZSBwYXJhbGxlbCBwbGFuZXMgbW9kZWwgYXJlIGxpc3RlZCBiZWxvdy4KCihJbnRlcmNlcHQpICAgICAgICBGb29kICAgICBTZXJ2aWNlICAgICAgICBFYXN0IAotMjAuODE1NDc2MSAgIDEuNDg2MjcyNSAgIDEuNjY0Njg4NCAgIDAuOTY0ODgxNCAKCldoaWNoIG9mIHRoZSBmb2xsb3dpbmcgc3RhdGVtZW50cyBpcyAqKkZBTFNFKio/CgpSZWFzb24gYWJvdXQgdGhlIG1hZ25pdHVkZSBvZiB0aGUgYEVhc3RgIGNvZWZmaWNpZW50LgoKKipQb3NzaWJsZSBBbnN3ZXJzKioKCjEuIFRoZSBwcmVtaXVtIGZvciBiZWluZyBvbiB0aGUgRWFzdCBzaWRlIG9mIDV0aCBBdmVudWUgaXMganVzdCBsZXNzIHRoYW4gYSBkb2xsYXIsIGFmdGVyIGNvbnRyb2xsaW5nIGZvciB0aGUgcXVhbGl0eSBvZiBmb29kIGFuZCBzZXJ2aWNlLgoKMi4gVGhlIGltcGFjdCBvZiBsb2NhdGlvbiBpcyByZWxhdGl2ZWx5IHNtYWxsLCBzaW5jZSBvbmUgYWRkaXRpb25hbCByYXRpbmcgcG9pbnQgb2YgZWl0aGVyIGZvb2Qgb3Igc2VydmljZSB3b3VsZCByZXN1bHQgaW4gYSBoaWdoZXIgZXhwZWN0ZWQgcHJpY2UgdGhhbiBtb3ZpbmcgYSByZXN0YXVyYW50IGZyb20gdGhlIFdlc3Qgc2lkZSB0byB0aGUgRWFzdCBzaWRlLgoKMy4gVGhlIGV4cGVjdGVkIHByaWNlIG9mIGEgbWVhbCBvbiB0aGUgRWFzdCBzaWRlIGlzIGFib3V0IDk2JSBvZiB0aGUgY29zdCBvZiBhIG1lYWwgb24gdGhlIFdlc3Qgc2lkZSwgYWZ0ZXIgY29udHJvbGxpbmcgZm9yIHRoZSBxdWFsaXR5IG9mIGZvb2QgYW5kIHNlcnZpY2UuCgpBbnN3ZXI6IDMKCiMjIyAqKkltcGFjdCBvZiBsb2NhdGlvbioqIAoKVGhlIGltcGFjdCBvZiBsb2NhdGlvbiBicmluZ3MgdXMgdG8gYSBtb2RlbGluZyBxdWVzdGlvbjogc2hvdWxkIHdlIGtlZXAgdGhpcyB2YXJpYWJsZSBpbiBvdXIgbW9kZWw/IEluIGEgbGF0ZXIgY291cnNlLCB5b3Ugd2lsbCBsZWFybiBob3cgd2UgY2FuIGNvbmR1Y3QgZm9ybWFsIGh5cG90aGVzaXMgdGVzdHMgdG8gaGVscCB1cyBhbnN3ZXIgdGhhdCBxdWVzdGlvbi4gSW4gdGhpcyBjb3Vyc2UsIHdlIHdpbGwgZm9jdXMgb24gdGhlIHNpemUgb2YgdGhlIGVmZmVjdC4gSXMgdGhlIGltcGFjdCBvZiBsb2NhdGlvbiBiaWcgb3Igc21hbGw/CgpPbmUgd2F5IHRvIHRoaW5rIGFib3V0IHRoaXMgd291bGQgYmUgaW4gdGVybXMgb2YgdGhlIHByYWN0aWNhbCBzaWduaWZpY2FuY2UuIElzIHRoZSB2YWx1ZSBvZiB0aGUgY29lZmZpY2llbnQgbGFyZ2UgZW5vdWdoIHRvIG1ha2UgYSBkaWZmZXJlbmNlIHRvIHlvdXIgYXZlcmFnZSBwZXJzb24/IFRoZSB1bml0cyBhcmUgaW4gZG9sbGFycyBzbyBpbiB0aGlzIGNhc2UgdGhpcyBxdWVzdGlvbiBpcyBub3QgaGFyZCB0byBncmFzcC4KCkFub3RoZXIgd2F5IGlzIHRvIGV4YW1pbmUgdGhlIGltcGFjdCBvZiBsb2NhdGlvbiBpbiB0aGUgY29udGV4dCBvZiB0aGUgdmFyaWFiaWxpdHkgb2YgdGhlIG90aGVyIHZhcmlhYmxlcy4gV2UgY2FuIGRvIHRoaXMgYnkgYnVpbGRpbmcgb3VyIHBhcmFsbGVsIHBsYW5lcyBpbiAzRCBhbmQgc2VlaW5nIGhvdyBmYXIgYXBhcnQgdGhleSBhcmUuIEFyZSB0aGUgcGxhbmVzIGNsb3NlIHRvZ2V0aGVyIG9yIGZhciBhcGFydD8gRG9lcyB0aGUgYEVhc3RgIHZhcmlhYmxlIGNsZWFybHkgc2VwYXJhdGUgdGhlIGRhdGEgaW50byB0d28gZGlzdGluY3QgZ3JvdXBzPyBPciBhcmUgdGhlIHBvaW50cyBhbGwgbWl4ZWQgdXAgdG9nZXRoZXI/CgpgYGB7ciwgZWNobyA9IEZBTFNFfQptb2QgPC0gbG0oUHJpY2UgfiBGb29kICsgU2VydmljZSwgZGF0YSA9IG55YykKeCA8LSBzZXFfcmFuZ2UobnljJEZvb2QsIG4gPSA1MCkKeSA8LSBzZXFfcmFuZ2UobnljJFNlcnZpY2UsIG4gPSA1MCkKdzAgPC0gcmVwKDAsIDUwKQp3MSA8LSByZXAoMSwgNTApCnBsYW5lMCA8LSBtYXRyaXgobnJvdyA9IDUwLCBuY29sID0gNTApCnBsYW5lMSA8LSBtYXRyaXgobnJvdyA9IDUwLCBuY29sID0gNTApCmZvciAoaSBpbiBzZXFfYWxvbmcoeCkpIHsKICBwbGFuZTBbaSwgXSA8LSBwcmVkaWN0KG1vZCwgbmV3ZGF0YSA9IGRhdGEuZnJhbWUoRm9vZCA9IHgsIFNlcnZpY2UgPSB5W2ldLCBFYXN0ID0gdzApKQp9CmZvciAoaSBpbiBzZXFfYWxvbmcoeCkpIHsKICBwbGFuZTFbaSwgXSA8LSBwcmVkaWN0KG1vZCwgbmV3ZGF0YSA9IGRhdGEuZnJhbWUoRm9vZCA9IHgsIFNlcnZpY2UgPSB5W2ldLCBFYXN0ID0gdzEpKQp9CmBgYAoKKipJbnN0cnVjdGlvbnMqKgoKLSBVc2UgYHBsb3RfbHlgIHRvIGRyYXcgM0Qgc2NhdHRlcnBsb3QgZm9yIGBQcmljZWAgYXMgYSBmdW5jdGlvbiBvZiBgRm9vZGAsIGBTZXJ2aWNlYCwgYW5kIGBFYXN0YCBieSBtYXBwaW5nIHRoZSBgemAgdmFyaWFibGUgdG8gdGhlIHJlc3BvbnNlIGFuZCB0aGUgYHhgIGFuZCBgeWAgdmFyaWFibGVzIHRvIHRoZSBudW1lcmljIGV4cGxhbmF0b3J5IHZhcmlhYmxlcy4gVXNlIGNvbG9yIHRvIGluZGljYXRlIHRoZSB2YWx1ZSBvZiBgRWFzdGAuIFBsYWNlIGBGb29kYCBvbiB0aGUgeC1heGlzIGFuZCBgU2VydmljZWAgb24gdGhlIHktYXhpcy4KLSBVc2UgYGFkZF9zdXJmYWNlKClgICh0d2ljZSkgdG8gZHJhdyB0d28gcGxhbmVzIHRocm91Z2ggdGhlIGNsb3VkIG9mIHBvaW50cywgb25lIGZvciByZXN0YXVyYW50cyBvbiB0aGUgV2VzdCBzaWRlIGFuZCBhbm90aGVyIGZvciByZXN0YXVyYW50cyBvbiB0aGUgRWFzdCBzaWRlLiBVc2UgdGhlIG9iamVjdHMgYHBsYW5lMGAgYW5kIGBwbGFuZTFgLgoKYGBge3J9CiMgZHJhdyAzRCBzY2F0dGVycGxvdApwIDwtIHBsb3RfbHkoZGF0YSA9IG55YywgeiA9IH5QcmljZSwgeCA9IH5Gb29kLCB5ID0gflNlcnZpY2UsIG9wYWNpdHkgPSAwLjYpICU+JQogIGFkZF9tYXJrZXJzKGNvbG9yID0gfmZhY3RvcihFYXN0KSwgbWFya2VyID0gbGlzdChzaXplID0gMikpIAoKIyBkcmF3IHR3byBwbGFuZXMKcCAlPiUKICBhZGRfc3VyZmFjZSh4ID0gfngsIHkgPSB+eSwgeiA9IH5wbGFuZTAsIHNob3dzY2FsZSA9IEZBTFNFKSAlPiUKICBhZGRfc3VyZmFjZSh4ID0gfngsIHkgPSB+eSwgeiA9IH5wbGFuZTEsIHNob3dzY2FsZSA9IEZBTFNFKQpgYGAKCiMjIyAqKkZ1bGwgbW9kZWwqKgoKT25lIHZhcmlhYmxlIHdlIGhhdmVuJ3QgY29uc2lkZXJlZCBpcyBgRGVjb3JgLiBEbyBwZW9wbGUsIG9uIGF2ZXJhZ2UsIHBheSBtb3JlIGZvciBhIG1lYWwgaW4gYSByZXN0YXVyYW50IHdpdGggbmljZXIgZGVjb3I/IElmIHNvLCBkb2VzIGl0IHN0aWxsIG1hdHRlciBhZnRlciBjb250cm9sbGluZyBmb3IgdGhlIHF1YWxpdHkgb2YgZm9vZCwgc2VydmljZSwgYW5kIGxvY2F0aW9uPwoKQnkgYWRkaW5nIGEgdGhpcmQgbnVtZXJpYyBleHBsYW5hdG9yeSB2YXJpYWJsZSB0byBvdXIgbW9kZWwsIHdlIGxvc2UgdGhlIGFiaWxpdHkgdG8gdmlzdWFsaXplIHRoZSBtb2RlbCBpbiBldmVuIHRocmVlIGRpbWVuc2lvbnMuIE91ciBtb2RlbCBpcyBub3cgYSBbaHlwZXJwbGFuZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvSHlwZXJwbGFuZSkgLS0gb3IgcmF0aGVyLCBwYXJhbGxlbCBoeXBlcnBsYW5lcyAtLSBhbmQgd2hpbGUgd2Ugd29uJ3QgZ28gYW55IGZ1cnRoZXIgd2l0aCB0aGUgZ2VvbWV0cnksIGtub3cgdGhhdCB3ZSBjYW4gY29udGludWUgdG8gYWRkIGFzIG1hbnkgdmFyaWFibGVzIHRvIG91ciBtb2RlbCBhcyB3ZSB3YW50LiBBcyBodW1hbnMsIG91ciBzcGF0aWFsIHZpc3VhbGl6YXRpb24gYWJpbGl0eSB0YXBzIG91dCBhZnRlciB0aHJlZSBudW1lcmljIHZhcmlhYmxlcyAobWF5YmUgeW91IGNvdWxkIGFyZ3VlIGZvciBmb3VyLCBidXQgY2VydGFpbmx5IG5vIGZ1cnRoZXIpLCBidXQgbmVpdGhlciB0aGUgbWF0aGVtYXRpY2FsIGVxdWF0aW9uIGZvciB0aGUgcmVncmVzc2lvbiBtb2RlbCwgbm9yIHRoZSBmb3JtdWxhIHNwZWNpZmljYXRpb24gZm9yIHRoZSBtb2RlbCBpbiBSLCBpcyBib3RoZXJlZCBieSB0aGUgaGlnaGVyIGRpbWVuc2lvbmFsaXR5LgoKVXNlIGBsbSgpYCB0byBmaXQgYSBwYXJhbGxlbCBwbGFuZXMgbW9kZWwgZm9yIGBQcmljZWAgYXMgYSBmdW5jdGlvbiBvZiBgRm9vZGAsIGBTZXJ2aWNlYCwgYERlY29yYCwgYW5kIGBFYXN0YC4KCmBgYHtyfQpsbShQcmljZSB+IEZvb2QgKyBTZXJ2aWNlICsgRGVjb3IgKyBFYXN0LCBkYXRhID0gbnljKQpjb3IobnljWywgLTJdKQpgYGAKCk5vdGljZSB0aGUgZHJhbWF0aWMgY2hhbmdlIGluIHRoZSB2YWx1ZSBvZiB0aGUgYFNlcnZpY2VgIGNvZWZmaWNpZW50LgoKV2hpY2ggb2YgdGhlIGZvbGxvd2luZyBpbnRlcnByZXRhdGlvbnMgaXMgaW52YWxpZD8KCioqUG9zc2libGUgQW5zd2VycyoqCgoxLiBTaW5jZSB0aGUgcXVhbGl0eSBvZiBmb29kLCBkZWNvciwgYW5kIHNlcnZpY2Ugd2VyZSBhbGwgc3Ryb25nbHkgY29ycmVsYXRlZCwgbXVsdGljb2xsaW5lYXJpdHkgaXMgdGhlIGxpa2VseSBleHBsYW5hdGlvbi4KCjIuIE9uY2Ugd2UgY29udHJvbCBmb3IgdGhlIHF1YWxpdHkgb2YgZm9vZCwgZGVjb3IsIGFuZCBsb2NhdGlvbiwgdGhlIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gY29udmV5ZWQgYnkgc2VydmljZSBpcyBuZWdsaWdpYmxlLgoKMy4gU2VydmljZSBpcyBub3QgYW4gaW1wb3J0YW50IGZhY3RvciBpbiBkZXRlcm1pbmluZyB0aGUgcHJpY2Ugb2YgYSBtZWFsLgoKNC4gTm9uZSBvZiB0aGUgYWJvdmUuCgpBbnN3ZXI6IDMKCiMjICoqMS4gV3JhcC11cCoqCgpUaGFua3MgZm9yIHRha2luZyB0aGlzIGNvdXJzZSBvbiBtdWx0aXBsZSBhbmQgbG9naXN0aWMgcmVncmVzc2lvbiB3aXRoIHVzLiBXZSBob3BlIHRoYXQgeW91J3ZlIGZvdW5kIHRoaXMgY291cnNlIHRvIGJlIGlsbHVtaW5hdGluZyBhbmQgdXNlZnVsLiBZb3UgbGVhcm5lZCBhYm91dCBhIHZhcmlldHkgb2YgbXVsdGlwbGUgcmVncmVzc2lvbiBtb2RlbHMgYnkgZm9jdXNpbmcgb24gdGhlIGludGVycGxheSBiZXR3ZWVuIHRoZSBtYXRoZW1hdGljYWwsIGdlb21ldHJpYywgYW5kIHN5bnRhY3RpY2FsIHJlcHJlc2VudGF0aW9ucyBvZiB0aGVzZSBtb2RlbHMuIFlvdSBleHRlbmRlZCBtYW55IG9mIHRob3NlIHNhbWUgaWRlYXMgdG8gbG9naXN0aWMgcmVncmVzc2lvbiwgd2hpY2ggY292ZXJzIHRoZSBjYXNlIGluIHdoaWNoIHdlIGhhdmUgYSBiaW5hcnkgcmVzcG9uc2UgdmFyaWFibGUuIFdlIGRpc2N1c3NlZCB0aGlzIG1hdGVyaWFsIGFzIGEgYnJhbmNoIG9mIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MuIFRoYXQgaXMsIHdlIGZvY3VzZWQgb24gaG93IHRoZSBtb2RlbHMgd29yaywgaG93IHdlIHNob3VsZCBpbnRlcnByZXQgdGhlbSwgYW5kIGhvdyB0aGV5IGNhbiBiZSB1c2VkLCBidXQgd2UgZGlkbid0IHRhbGsgYXQgYWxsIGFib3V0IGluZmVyZW5jZS4gU3RhdGlzdGljaWFucyBoYXZlIGRldmVsb3BlZCBtYW55IHRlY2huaXF1ZXMgZm9yIHBlcmZvcm1pbmcgaW5mZXJlbmNlIG9uIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZXNlIHJlZ3Jlc3Npb24gbW9kZWxzLiBUaG9zZSB0ZWNobmlxdWVzIGhlbHAgdXMgYW5zd2VyIHF1ZXN0aW9ucyBhYm91dCB3aGV0aGVyIHRoZSBlZmZlY3RzIHdlIG9ic2VydmUgYXJlIHdpdGhpbiB0aGUgcmVhbG0gb2Ygc3RhdGlzdGljYWwgbm9pc2UsIG9yIG5vdC4gV2l0aG91dCBpbmZlcmVuY2UsIHdlIGNhbiBvbmx5IHN0YXRlIGhvdyBiaWcgdGhlIGVmZmVjdCB3ZSBvYnNlcnZlZCB3YXMtLS13ZSBjYW4ndCBtYWtlIGFueSBjbGFpbXMgYWJvdXQgd2hldGhlciB0aGF0IGVmZmVjdCB3YXMgbGlrZWx5IHRoZSByZXN1bHQgb2YgY2hhbmNlIGFsb25lLCBvciB3aGV0aGVyIGl0IHJlcHJlc2VudHMgYSBtZWFuaW5nZnVsIGNoYXJhY3Rlcml6YXRpb24gb2YgdGhlIHVuZGVybHlpbmcgcGhlbm9tZW5vbi4gVG8gY29tcGxldGUgeW91ciB1bmRlcnN0YW5kaW5nLCB5b3Ugc2hvdWxkIGxlYXJuIGFib3V0IGluZmVyZW50aWFsIHRlY2huaXF1ZXMgZm9yIHJlZ3Jlc3Npb24gaW4gYW5vdGhlciBEYXRhQ2FtcCBjb3Vyc2UuIEl0J3MgYmVlbiBteSBwbGVhc3VyZSB0byBiZSB5b3VyIGluc3RydWN0b3IgZm9yIHRoaXMgY291cnNlLS0taGF2ZSBhIGdyZWF0IGRheSE=